\chapter{Design Patterns}
%
Design patterns are reusable solutions to common software design problems.
Typically, design patterns are not `drop in' solutions to a given problem, but
instead provide a framework for how a software engineer might best solve a
particular problem. Although many of the design pattern implementations provided
in the Gang of Four's \textit{Design Patterns: Elements of Reusable
Object-Oriented Software} make assumptions about language features which do not
exist in Python (e.g. static typing and interfaces), many of the patterns
covered are still applicable to dynamically typed languages albeit with some
modifications.

Throughout the development of the CEAB++ application, a number of design
patterns were employed to reduce code duplication, minimize software defects,
and most importantly, avoid re-inventing the wheel. The design patterns used
include: Decorator, Proxy, Iterator and Observer.
%Ben: feel free to add more or change this list as you see fit. I was only going
%to provide a brief write-up of the first two.

\section{Decorator}

Python implements function and method decorators as a feature of the language.
Decorators are used to add additional functionality to functions or methods in
Python by wrapping the defined function dynamically in another function which
provides some functionality that is executed before or after the defined
function. In the CEAB++ application, decorators are used primarily for
authentication purposes. Views that are protected by some level of
authentication are wrapped in decorators that check the current
user's permissions and evaluates whether they have access to the requested
resource. An example of the definition of a decorator and its use is included
below.

%Include here!

\begin{verbatim}
### Definition and use of decorator pattern

### definition of owner_required pattern
class owner_required(object):
    """Checks to see whether the current user
    is the owner of the requested object
    """

    def __init__(self, id_keyword, object_model):
        self.id_keyword = id_keyword
        self.object_model = object_model

    def __call__(self, f):
        def newf(request, **kwargs):
            u = request.user
            if not u.is_authenticated():
                return HttpResponseRedirect(reverse('login'))
            object_id = kwargs[self.id_keyword]
            # retrieve object from database
            object = get_object_or_404(self.object_model, id=object_id)
            session_key = repr(object)
            # check session for ownership
            if request.session.get(session_key, False):
                kwargs['object'] = object
                return f(request, **kwargs)
            # check if current user is the owner
            elif object.is_owner(u): 
                request.session[session_key] = True
                kwargs['object'] = object
                return f(request, **kwargs)
            else:
                return render_to_response('denied.html',
                        context_instance=RequestContext(request))
        return newf


### use of owner_required pattern in view
@owner_required('plan_id', Plan)
def validate_plan(request, plan_id, object=None):
    #plan = get_object_or_404(Plan, id=plan_id)
    plan = object

    errors = plan.get_errors()

    return render_to_response(
            'plan/validation_results.html',
            {'errors': errors},
            context_instance=RequestContext(request))

\end{verbatim}
Django also provides a number of decorators that are useful. When a user is
registered, several objects must be created in sequence
for the registration to be
successful. In order to maintain database integrity if one of the objects fails,
the database should be rolled back to its original state. This is done by the
use of transactions. Instead of manually coding the start and end of the
transaction, this is more concisely achieved by the use of the
commmit\_on\_sucess decorator, as shown below.

\begin{verbatim}
@transaction.commit_on_success
def register(request):
\end{verbatim}


\section{Proxy}

Django uses an object relational mapper (ORM) to provide access to the underlying
relational data behind the CEAB++. This ORM is a proxy to the database and its
objects. Instead of directly executing SQL calls that vary depending on the
database used as a backend (MySQL, SQLLite, etc.), a standard interface is used
through the ORM that hides these implementation details. 

In addition, the query manager returns lazy querysets when invoked. This means
that evaluation of the query and a call to a database is deferred until
absolutely necessary. In the meantime, the queryset acts as a proxy to the
actual objects contained in the query. The queryset may be filtered further
before the database is called, or if the queryset is never used, it will never
be evaluated, and unnecessary database calls are not made.

Proxies are also used in the permissions system. The most important permission
that must be considered is whether a particular user has access to a given Plan.
Instead of checking if a student owns a plan every single time the plan is
accessed, if a user successfully accesses a plan, this permission is stored in
the user's session through Django's sessions framework. Subsequent permissions
requests use this session variable as a proxy to determine whether or not the
user has permission or not. If the session variable indicates that the user has
permission, further lookups are not performed. If the session variable does not
have permissions information, the full lookup is performed and the session
variable is set. In this way the session stands in for a full permissions lookup
and reduces the load on the database.

\section{Observer}

Django has a built-in convention for implementing the observer pattern on
database objects called the signals framework. By default Django provides many
useful signals such as an object being saved, deleted, instantiated, etc. By
registering a method to one of these signals, the observer pattern is easily
implemented.

In CEAB++, the observer pattern is used for automating some of the scheduling
choices that users have to make. Whenever a course is added to a student's plan,
any scheduling data for that course is also added to the student's schedule. In
this way the student's schedule object is observing its plan object for any
changes, and responding by adding course offerings and timeslots when
appropriate.

Signals are also used from a developer's perspective to improve debugging and
exception handling. A signal handler is attached to the signal that is triggered
when an exception is raised by a web request. The exception is then logged to
the system log for review by an administrator.

